package com.three.box.fragment

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.EditText
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.LinearLayoutCompat
import androidx.core.content.ContextCompat
import androidx.core.text.isDigitsOnly
import androidx.fragment.app.Fragment
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.input.getInputField
import com.afollestad.materialdialogs.input.input
import com.afollestad.materialdialogs.list.listItems
import com.alibaba.fastjson2.JSONArray
import com.alibaba.fastjson2.JSONObject
import com.google.gson.Gson
import com.hjq.toast.Toaster
import com.tencent.mmkv.MMKV
import com.three.box.R
import com.three.box.activity.AddProductActivity
import com.three.box.activity.RecordListActivity
import com.three.box.config.Constant
import com.three.box.databinding.FragmentInBoxBinding
import com.three.box.dialog.GroupDialogFragment
import com.three.box.entity.ApiResult
import com.three.box.entity.Box
import com.three.box.entity.LoginResult
import com.three.box.entity.OperateType
import com.three.box.entity.Product
import com.three.box.entity.ProductConfig
import com.three.box.entity.ProductModel
import com.three.box.entity.UserInfo
import com.three.box.helper.LogUtils
import com.three.box.network.AppRepository
import com.three.box.network.NetworkUtil
import com.three.box.widget.WaitDialog
import kotlin.collections.set


class InBoxFragment : Fragment() {

    private lateinit var binding: FragmentInBoxBinding

    companion object {
        private const val TAG = "InBoxFragment"
        @JvmStatic
        fun newInstance() = InBoxFragment()
    }

    private var waitDialog: WaitDialog? = null

    private val originalList = mutableListOf<Product>()
    private val productList = mutableListOf<Product>()
    private val checkedProductList = mutableListOf<Product>()
    private var box: Box? = null
    private var isVisitor = false

    private lateinit var addProductLaunch: ActivityResultLauncher<Intent>
    private lateinit var addProductFromHistoryLaunch: ActivityResultLauncher<Intent>

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // Inflate the layout for this fragment
        binding = FragmentInBoxBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        waitDialog = WaitDialog(requireContext())
        val temp = MMKV.defaultMMKV().decodeString(Constant.LOGIN_RESULT, "{}")
        val loginResult = Gson().fromJson(temp, LoginResult::class.java)
        if (loginResult.userInfo?.role == 2) {
            isVisitor = true
        }

        initViews()

        addProductLaunch = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
            // 获取到Activity回传的数据
            if(activityResult.resultCode != Activity.RESULT_OK) {
                return@registerForActivityResult
            }
            onNewProductsAdded(activityResult)
        }
        addProductFromHistoryLaunch = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
            // 获取到Activity回传的数据
            if(activityResult.resultCode != Activity.RESULT_OK) {
                return@registerForActivityResult
            }
            onNewProductsAdded(activityResult)
        }
        resetValues()
    }

    private fun initViews() {
        binding.inBtn.visibility = if (isVisitor) View.GONE else View.VISIBLE
        binding.outBtn.visibility = if (isVisitor) View.GONE else View.VISIBLE
        binding.selectAllCb.visibility = if (isVisitor) View.GONE else View.VISIBLE
        // 入库
        binding.inBtn.setOnClickListener {
            showNoteDialog(1)
        }
        // 出库
        binding.outBtn.setOnClickListener {
            if (!isAllNewAdded()) {
                Toaster.show("包含新增物品，无法出库")
                return@setOnClickListener
            }
            showNoteDialog(2)
        }
        binding.selectAllCb.setOnCheckedChangeListener { _, isChecked ->
            if (isChecked) {
                checkedProductList.clear()
                checkedProductList.addAll(productList)
                binding.selectAllCb.text = getString(R.string.deselect_all)
            } else {
                checkedProductList.clear()
                binding.selectAllCb.text = getString(R.string.select_all)
            }
            resetValues()
        }
    }

    private fun convertConfig2Product(productConfigList: List<ProductConfig>) {
        fun existModel(productModel: ProductModel): Boolean {
            return productList.find {
                it.productId == productModel.productId.toInt()
                        && it.productModelId == productModel.id
            } != null
        }

        val groupList = AppRepository.instance.productGroupList
        productConfigList.forEach { productConfig ->
            val group = groupList[0]
            productConfig.productModels.forEach label@{  productModel ->
                if (!productModel.checked) {
                    return@label
                }
                if (existModel(productModel)) {
                    return@label
                }
                productList.add(Product(
                    productId = productConfig.id,
                    productName = productConfig.name,
                    productDesc = productConfig.desc,
                    productModelId = productModel.id,
                    number = 1,
                    groupId = group.id,
                    groupName = group.name,
                    productModelName = productModel.name
                ))
            }
        }
    }

    fun addProduct() {
        if (box == null) {
            Toaster.show("请先扫码箱子二维码")
            return
        }
        val existProductIds = productList.map { it.productId }
        val intent = Intent(requireActivity(), AddProductActivity::class.java)
        intent.putIntegerArrayListExtra("product_ids", ArrayList(existProductIds))
        addProductLaunch.launch(intent)
    }

    fun addProductFromHistory(currentBoxId: Int) {
        if (box == null) {
            Toaster.show("请先扫码箱子二维码")
            return
        }
        val intent = Intent(requireActivity(), RecordListActivity::class.java)
        intent.putExtra("box_id", currentBoxId)
        addProductFromHistoryLaunch.launch(intent)
    }

    @Suppress("DEPRECATION")
    private fun onNewProductsAdded(activityResult: ActivityResult) {
        val data = activityResult.data
        val resultList: ArrayList<Product>? = if (Build.VERSION.SDK_INT <  Build.VERSION_CODES.TIRAMISU)
            data?.getParcelableArrayListExtra("product_list")
        else
            data?.getParcelableArrayListExtra("product_list", Product::class.java)
        fun existProduct(product: Product): Boolean {
            return productList.find {
                it.productId == product.productId
                        && it.productModelId == product.productModelId
            } != null
        }
        resultList?.let {  list ->
            list.forEach { product ->
                if (!existProduct(product)) {
                    productList.add(product)
                }
            }
            resetValues()
        }
    }

    @SuppressLint("CheckResult")
    private fun showNoteDialog(type: Int) {
        if (box == null) {
            Toaster.show("数据错误，请检查后重试")
            return
        }
        if (checkedProductList.size <= 0) {
            Toaster.show("请先选择物品")
            return
        }
        MaterialDialog(requireContext()).show {
            title(R.string.add_note_title)
            input()
            noAutoDismiss()
            cancelOnTouchOutside(false)
            negativeButton(R.string.cancel) {
                it.dismiss()
            }
            positiveButton(R.string.confirm) {
                it.dismiss()
                val note = it.getInputField().text.toString()
                showOperateTypeDialog(type, note)
            }
        }
    }

    @SuppressLint("CheckResult")
    private fun showOperateTypeDialog(type: Int, note: String) {
        val repository = AppRepository.instance
        val list = repository.loadOperateType().filter { it.type == type }
        if (list.isEmpty()) {
            repository.reloadOperateType(1)
            repository.reloadOperateType(2)
            Toaster.show("数据加载中，请稍后")
            return
        }
        val names = list.map { it.name }
        MaterialDialog(requireContext()).show {
            title(R.string.operate_type)
            cancelOnTouchOutside(false)
            listItems(items = names, selection = { _, index, _ ->
                val operateType = list[index]
                LogUtils.d(TAG, "selected operate type is $operateType")
                commit(type, operateType, note)
            })
        }
    }

    private fun commit(type: Int, operateType: OperateType, note: String) {
        waitDialog?.show()
        val boxId = box!!.id

        val boxObj = JSONObject()
        boxObj["id"] = boxId
        boxObj["status"] = type
        boxObj["operateType"] = operateType.type
        boxObj["notes"] = note
        val productArrayObj = JSONArray()
        checkedProductList.forEach { product ->
            if (product.number <= 0) {
                return@forEach
            }
            val productObj = JSONObject()
            productObj["productId"] = product.productId
            productObj["productModelId"] = product.productModelId
            productObj["groupId"] = product.groupId
            productObj["number"] = product.number
            productObj["notes"] = ""

            productArrayObj.add(productObj)
        }
        boxObj["products"] = productArrayObj

        LogUtils.d(TAG, boxObj.toJSONString())
        AppRepository.instance.saveBox(boxObj) { code, msg ->
            waitDialog?.dismiss()
            Toaster.show(msg)
            if (code == ApiResult.SUCCESS) {
                checkedProductList.clear()
                originalList.clear()
                binding.selectAllCb.isChecked = false
                AppRepository.instance.resetConfig()
                loadBoxInfo(box!!.boxId)
            }
        }
    }

    private fun isAllNewAdded(): Boolean {
        checkedProductList.forEach { product ->
            if (!originalList.contains(product)) {
                return false
            }
        }

        return true
    }

    fun onBoxLoaded(newBox: Box) {
        box = newBox
        originalList.clear()
        originalList.addAll(newBox.products)
        newBox.products.removeIf { it.number <= 0 }

        productList.clear()
        productList.addAll(newBox.products)
        resetValues()
    }

    private fun resetValues() {
        if (box == null) {
            // show empty view
            binding.emptyLayout.visibility = View.VISIBLE
            binding.scrollView.visibility = View.GONE
            binding.selectAllCb.visibility = View.GONE
            binding.descTv.text = getString(R.string.no_box_data)
            return
        }
        if (productList.isEmpty()) {
            // show empty view
            binding.emptyLayout.visibility = View.VISIBLE
            binding.scrollView.visibility = View.GONE
            binding.selectAllCb.visibility = View.GONE
            binding.descTv.text = getString(R.string.no_product_data)
            return
        }
        binding.emptyLayout.visibility = View.GONE
        binding.selectAllCb.visibility = if (isVisitor) View.GONE else View.VISIBLE
        binding.scrollView.visibility = View.VISIBLE
        with(binding) {
            contentLayout.removeAllViews()
        }
        productList.sortBy { it.productId }

        productList.forEachIndexed { index, product ->
            binding.contentLayout.addView(buildItem(index, product))
        }
    }

    private val whiteColor = android.R.color.white
    private val blackColor = android.R.color.black

    private fun textColor(white: Boolean): Int {
        return if (white) ContextCompat.getColor(
            requireContext(),
            blackColor
        ) else ContextCompat.getColor(requireContext(), whiteColor)
    }

    private fun buildItem(index: Int, product: Product): View {
        val itemView = View.inflate(requireContext(), R.layout.item_normal, null)

        val productCb = itemView.findViewById<CheckBox>(R.id.product_cb)
        productCb.visibility = if (isVisitor) View.GONE else View.VISIBLE
        productCb.isChecked = checkedProductList.contains(product)
        productCb.setOnCheckedChangeListener { _, isChecked ->
            if (isChecked) {
                checkedProductList.add(product)
            } else {
                checkedProductList.remove(product)
            }
            if (checkedProductList.size == productList.size) {
                binding.selectAllCb.isChecked = true
            } else if (checkedProductList.size == 0) {
                binding.selectAllCb.isChecked = false
            }
//            binding.selectAllCb.isChecked = checkedProductList.size == productList.size
        }

        val group = AppRepository.instance.productGroupList.find { it.id == product.groupId }
        var isBgWhite = false
        if (group != null) {
            val myShapeView: View = itemView.findViewById(R.id.item_product)
            val shapeDrawable = myShapeView.background as GradientDrawable

            isBgWhite = "#ffffff".equals(group.color, ignoreCase = true)
            shapeDrawable.setColor(Color.parseColor(group.color))
        }

        val descTv = itemView.findViewById<TextView>(R.id.desc_tv)
        descTv.setTextColor(textColor(isBgWhite))
        descTv.text = getString(R.string.format_name, product.productDesc)

        val modelTv = itemView.findViewById<TextView>(R.id.model_tv)
        modelTv.setTextColor(textColor(isBgWhite))
        modelTv.text = getString(R.string.format_model, product.productModelName)

        val numberTv = itemView.findViewById<TextView>(R.id.number_tv)
        numberTv.setTextColor(textColor(isBgWhite))
        val numberEt = itemView.findViewById<EditText>(R.id.number_et)
        numberEt.isEnabled = !isVisitor
        numberEt.setTextColor(textColor(isBgWhite))
        numberEt.text = Editable.Factory.getInstance().newEditable(product.number.toString())

        val groupTv = itemView.findViewById<TextView>(R.id.group_tv)
        groupTv.setTextColor(textColor(isBgWhite))
        groupTv.text = getString(R.string.format_group, product.groupName)
        val groupLayout = itemView.findViewById<LinearLayoutCompat>(R.id.group_layout)
        if (!isVisitor) {
            groupLayout.setOnClickListener {
                val groupDialog = GroupDialogFragment.newInstance()
                groupDialog.setCallback { group ->
                    product.groupId = group.id
                    product.groupName = group.name
                    groupTv.text = getString(R.string.format_group, product.groupName)
                    resetItem(index)
                }
                groupDialog.show(childFragmentManager, TAG)
            }
        }
        val arrowIv = itemView.findViewById<ImageView>(R.id.arrow_iv)
        arrowIv.setImageResource(if (isBgWhite) R.drawable.ic_arrow_drop_down_black else R.drawable.ic_arrow_drop_down)

        val minusIv = itemView.findViewById<ImageView>(R.id.minus_iv)
        minusIv.setImageDrawable(minusDrawable(isBgWhite))
        val plusIv = itemView.findViewById<ImageView>(R.id.plus_iv)
        plusIv.setImageDrawable(plusDrawable(isBgWhite))
        minusIv.visibility = if (isVisitor) View.GONE else View.VISIBLE
        plusIv.visibility = if (isVisitor) View.GONE else View.VISIBLE
        minusIv.setOnClickListener {
            val numberText = numberEt.text.toString()
            var number = 0
            if (numberText.isNotEmpty()) {
                if (!numberText.isDigitsOnly()) {
                    Toaster.show("请输入数字")
                    return@setOnClickListener
                }
                number = numberText.toInt()
            }
            number -= 1
            if(number < 0) {
                number = 0
            }
            product.number = number
            numberEt.text = Editable.Factory.getInstance().newEditable(number.toString())
        }
        plusIv.setOnClickListener {
            val numberText = numberEt.text.toString()
            var number = 0
            if (numberText.isNotEmpty()) {
                if (!numberText.isDigitsOnly()) {
                    Toaster.show("请输入数字")
                    return@setOnClickListener
                }
                number = numberText.toInt()
            }
            number += 1
            product.number = number
            numberEt.text = Editable.Factory.getInstance().newEditable(number.toString())
        }

        return itemView
    }

    private fun resetItem(index: Int) {
        binding.contentLayout.removeViewAt(index)
        binding.contentLayout.addView(buildItem(index, productList[index]), index)
    }

    private fun minusDrawable(white: Boolean): Drawable {
        val color = if (white) android.R.color.black else android.R.color.white
        val drawable = ContextCompat.getDrawable(requireContext(), R.drawable.ic_minus_circle)
        drawable!!.setTint(ContextCompat.getColor(requireContext(), color))

        return drawable
    }

    private fun plusDrawable(white: Boolean): Drawable {
        val color = if (white) android.R.color.black else android.R.color.white
        val drawable = ContextCompat.getDrawable(requireContext(), R.drawable.ic_plus_circle)
        drawable!!.setTint(ContextCompat.getColor(requireContext(), color))

        return drawable
    }


    private fun loadBoxInfo(boxId: String) {
        if (!NetworkUtil.isNetworkAvailable(requireContext())) {
            Toaster.show("网络错误，请检查后重试")
            return
        }
        AppRepository.instance.boxInfo(boxId) { code, box ->
            if (code != 0 || box == null) {
                Toaster.show("信息同步失败")
                return@boxInfo
            }
            onBoxLoaded(box)
        }
    }
}



















